﻿/**************************************************************
 *
 * 唯一标识：a8f6a11e-ed3c-4683-b46a-6fd4f710c2da
 * 命名空间：Sgr.BackGroundTasks
 * 创建时间：2023/9/1 6:30:54
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Microsoft.Extensions.Options;
using Quartz;
using Sgr.Utilities;

namespace Sgr.BackGroundTasks
{
    /// <summary>
    /// Quartz周期性任务执行器，用于执行所有注册的定时后台任务
    /// </summary>
    public class QuartzPeriodicJob : IJob
    {
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly IBackGroundTaskExecutor _backGroundTaskExecutor;
        private readonly BackGroundTaskOptions _backGroundTaskOptions;
        private readonly IBackGroundExceptionHandle _backGroundExceptionHandle;
        private readonly ILogger<QuartzPeriodicJob> _logger;

        /// <summary>
        /// 初始化QuartzPeriodicJob的新实例
        /// </summary>
        /// <param name="serviceScopeFactory">服务范围工厂</param>
        /// <param name="backGroundTaskExecutor">后台任务执行器</param>
        /// <param name="backGroundTaskOptions">后台任务配置选项</param>
        /// <param name="backGroundExceptionHandle">后台任务异常处理程序</param>
        /// <param name="logger">日志记录器</param>
        public QuartzPeriodicJob(
            IServiceScopeFactory serviceScopeFactory,
            IBackGroundTaskExecutor backGroundTaskExecutor,
            IOptions<BackGroundTaskOptions> backGroundTaskOptions,
            IBackGroundExceptionHandle backGroundExceptionHandle,
            ILogger<QuartzPeriodicJob> logger)
        {
            _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
            _backGroundTaskExecutor = backGroundTaskExecutor ?? throw new ArgumentNullException(nameof(backGroundTaskExecutor));
            _backGroundTaskOptions = backGroundTaskOptions?.Value ?? throw new ArgumentNullException(nameof(backGroundTaskOptions));
            _backGroundExceptionHandle = backGroundExceptionHandle ?? throw new ArgumentNullException(nameof(backGroundExceptionHandle));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 执行周期性后台任务
        /// </summary>
        /// <param name="context">作业执行上下文</param>
        public async Task Execute(IJobExecutionContext context)
        {
            // 获取任务类型名称
            var taskClassTypeName = context.MergedJobDataMap.GetString(QuartzBackGroundTaskManager.KEY_TASK_CLASS_TYPE) ?? "null";

            // 获取任务元数据
            BackGroundTaskMetadata taskMetadata;
            try
            {
                taskMetadata = _backGroundTaskOptions.GetBackGroundTaskMetadata(taskClassTypeName)
                    ?? throw new BackGroundTaskException($"类型名称：{taskClassTypeName} 未注册");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取任务元数据失败");
                return;
            }

            // 检查取消令牌
            if (context.CancellationToken.IsCancellationRequested)
            {
                _logger.LogWarning("任务在开始前已被取消: {TaskName}", taskMetadata.TaskName);
                return;
            }

            // 如果任务有输入参数，则解析参数
            object? inputData = null;
            if (taskMetadata.HasInputParameter)
            {
                //如果无法获取执行任务所需的数据，则退出
                string? rawData = context.MergedJobDataMap.GetString(QuartzBackGroundTaskManager.KEY_DATA_OBJECT);

                if (string.IsNullOrEmpty(rawData))
                {
                    _logger.LogError(
                             "周期性任务执行失败: 无法获取任务数据 - TaskName: {TaskName}, TaskType: {TaskType}",
                             taskMetadata.TaskName,
                             taskMetadata.TaskClassType.Name);
                    return;
                }

                try
                {
                    inputData = JsonHelper.DeserializeObject(taskMetadata.TaskDataType!, rawData);
                }
                catch (Exception ex)
                {
                    _logger.LogError(
                          ex,
                          "周期性任务执行失败: 任务数据反序列化失败 - TaskName: {TaskName}, Data: {Data}",
                          taskMetadata.TaskName,
                          rawData);
                }

                if (inputData == null)
                {
                    _logger.LogError(
                        "周期性任务执行失败: 任务数据为空 - TaskName: {TaskName}, Data: {Data}",
                        taskMetadata.TaskName,
                        rawData);
                    return;
                }
            }

            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var backGroundTaskContext = new BackGroundTaskContext(
                    scope.ServiceProvider,
                    taskMetadata.TaskClassType,
                    inputData);

                try
                {
                    await _backGroundTaskExecutor.ExecuteAsync(backGroundTaskContext, context.CancellationToken);
                }
                catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested)
                {
                    _logger.LogWarning("任务被取消: {TaskName}", taskMetadata.TaskName);
                }
                catch (Exception exception)
                {
                    _logger.LogError(exception,
                            "周期性任务执行失败: {TaskName} - 重试次数: {RetryCount}",
                            taskMetadata.TaskName,
                            context.RefireCount);

                    // 通知任务执行失败
                    try
                    {
                        await _backGroundExceptionHandle.OnTaskFailAsync(backGroundTaskContext, context.RefireCount);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(
                            ex,
                            "执行周期性任务失败处理程序时发生异常: {TaskName}",
                            taskMetadata.TaskName);
                    }
                }
            }
        }
    }
}